

#include <windows.h>

#include "blcommon.h"
#include "args.h"

#include "ModuleExport.h"

// $(_PLATCOMMONLIB)\$(_CPUINDPATH)\oal_blcommon.lib define DownloadImage as static,
// so copy oal_blcommon codes and export DownloadImage as global
BOOL DownloadImage (LPDWORD pdwImageStart, LPDWORD pdwImageLength, LPDWORD pdwLaunchAddr);
void BootImage(DWORD dwLaunchAddr);
BOOL InitUSBEthDevice(PBOOT_CFG pBootCfg, OAL_KITL_ARGS *pKITLArgs);
BOOL InitEbSimuDevice(PBOOT_CFG pBootCfg);
int OEMReadDebugByte(void);



typedef void (*pfnTst)();


PBOOT_CFG v_pBootCfg=NULL;

DWORD GetDebugStr(char* pBuf, DWORD dwLen, BOOL* pfEsc)
{
	DWORD i;
	char ch;

	pBuf[0]=0;
	dwLen--;
	for(i=0; i<dwLen; i++)
	{
		do
		{
			ch=OEMReadDebugByte();
		}while(-1==ch);

		if(ch == 0x1b)	// esc
		{
			if(pfEsc)
			{
				*pfEsc=TRUE;
			}
			return 0;
		}
		else if(ch == 0x8)	// backspace
		{
			if(i>0)
			{
				i-=2;
			}
			else
			{
				continue;
			}
		}
		else if(ch == '\r' || ch == '\n')
		{
			OEMWriteDebugByte(ch);
			break;
		}
		else
		{
			pBuf[i]=ch;
		}
		
		OEMWriteDebugByte(ch);

	}

	pBuf[i]=0;
	return i;
}

DWORD Str2Dword(char* pBuf, DWORD dwLen, BOOL* pfEsc)
{
	DWORD dwData[12];
	DWORD dwBase;
	DWORD dw, i, j;

	if(0!=dwLen)
	{
		if( (pBuf[0]=='0') 
			&& ( (pBuf[1]='x') || (pBuf[1]='X') ) )
		{
			i=2;
			dwBase=0x10;
		}
		else
		{
			i=0;
			dwBase=10;
		}

		for(j=0; i<dwLen && j<sizeof(dwData); i++, j++)
		{
			if(pBuf[i] >= '0' && pBuf[i] <= '9')
			{
				dwData[j]=pBuf[i]-'0';
			}
			else if(dwBase==0x10)
			{
				if(pBuf[i] >= 'a' && pBuf[i] <= 'f')
				{
					dwData[j]=pBuf[i]-'a'+0xa;
				}
				else if(pBuf[i] >= 'A' && pBuf[i] <= 'F')
				{
					dwData[j]=pBuf[i]-'A'+0xa;
				}
				else
				{
					dwLen=0;
					break;
				}
			}
			else
			{
				dwLen=0;
				break;
			}
		}
	}
	
	if(0==dwLen)
	{
		if(pfEsc)
		{
			*pfEsc=TRUE;
		}
	
		return 0xffffffff;
	}

	dw=0;
	for(i=0; i<j; i++)
	{
		dw*=dwBase;
		dw+=dwData[i];
	}

	return dw;
}

DWORD GetDebugDword(BOOL* pfEsc)
{
	char buf[11]={0};
	DWORD dwLen;
	dwLen=GetDebugStr(buf, sizeof(buf), pfEsc);
	return Str2Dword(buf, dwLen, pfEsc);
}


struct TstFunc
{
	pfnTst pfn;
	const char* pName;
};
#define TST_FUN(fun) {fun, #fun}
extern struct TstFunc s_TstFunS[];
void Tst_Main(PBOOT_CFG pBootCfg)
{
	DWORD i;
	char szFun[256];
	BOOL fFind;

	v_pBootCfg=pBootCfg;

	while(1)
	{
		EdbgOutputDebugString ( "\r\n=============\r\ntest functions:\r\n");
		for(i=0; ; i++)
		{
			if(s_TstFunS[i].pfn==NULL)
			{
				break;
			}
			EdbgOutputDebugString("\t%s\r\n", s_TstFunS[i].pName);
		}
		EdbgOutputDebugString("\tExit\r\n");
		EdbgOutputDebugString ( "Please enter functio name:\r\n");

		szFun[0]=0;
		GetDebugStr(szFun, sizeof(szFun), NULL);
		fFind=FALSE;

		if(0==strcmp("Exit", szFun))
		{
			break;
		}

		for(i=0; ; i++)
		{
			if(s_TstFunS[i].pfn==NULL)
			{
				break;
			}

			if(0==strcmp(s_TstFunS[i].pName, szFun))
			{
				EdbgOutputDebugString ( "\tdo test fun:%s\r\n", szFun);
				(*s_TstFunS[i].pfn)();
				fFind=TRUE;
				break;
			}
		}
		if(!fFind)
		{
			EdbgOutputDebugString ( "\tcan't find test function:%s\r\n", szFun);
		}

	}
}


extern BOOL g_fDisDbgPort;


BYTE* g_pCurLogAddr;
BOOL g_fStartLog;
BOOL g_fDisLog;
DWORD g_dwLogTimes;

extern PFN_OEMREPORTERROR      g_pOEMReportError;
extern BOOT_CFG	   g_BootConfig;
extern BSP_ARGS *pBSPArgs;


BOOL TestMenu(PBOOT_CFG pBootCfg);



#define LOG_BASE_ADDR 0xa1200000



DWORD g_dwLastRecAddr=0;
DWORD g_dwFirstDifRecAddr=0;
DWORD g_dwFirstDifBinAddr=0;
BYTE g_bFirstDifRecVal=0;
BYTE g_bFirstDifBinVal=0;
BOOL g_fFindDif=FALSE;

DWORD* g_pdwAsicEnd=(DWORD*)0x83b00000;

void AsicDbg()
{
	BYTE* pbBin=(BYTE*)0x82000000;
	BYTE* pbLstRec=(BYTE*)g_dwLastRecAddr;
	DWORD dwRecStart, dwRecLen, i;

	pbBin+=(7+4+4);	//sig+imgstart+imglen
	
	do
	{
		dwRecStart=Stream2Dword(pbBin);
		pbBin+=4;
		dwRecLen=Stream2Dword(pbBin);
		pbBin+=(4+4);	// rec_len+checksum

		// find first diff
		if(pbLstRec==dwRecStart)
		{
			for(i=0; i<dwRecLen; i++)
			{
				if(pbBin[i]!=pbLstRec[i])
				{
					g_dwFirstDifRecAddr=(pbLstRec+i);
					g_dwFirstDifBinAddr=(pbBin+i);
					g_bFirstDifRecVal=pbLstRec[i];
					g_bFirstDifBinVal=pbBin[i];
					g_fFindDif=TRUE;

					break;
				}
			}
		}

		pbBin+=dwRecLen;
	}while(dwRecStart<pbLstRec);
}

void AsicEndIndicate()
{
	DWORD i;
	for(i=0; i<100; i++)
	{
		g_pdwAsicEnd[1]=g_dwFirstDifRecAddr;
		g_pdwAsicEnd[2]=g_dwFirstDifBinAddr;
		g_pdwAsicEnd[3]=g_bFirstDifRecVal;
		g_pdwAsicEnd[4]=g_bFirstDifBinVal;
		g_pdwAsicEnd[0]=0x5a5a5a5a;
	}
	g_fDisDbgPort=FALSE;
EdbgOutputDebugString("AsicEndIndicate\r\n");
}


void  test_ram(int start, int len)
{
	int i, j, err=0;
	int* pi;

	for(j=0; j<2; j++)
	{
		EdbgOutputDebugString("start check ram bgn:0x%x, len:0x%x\r\n", start, len);

		pi=(int*)start;
		for(i=0; i<(len/4); i++, pi++)
		{
			j?(*pi=(~i)):(*pi=i);

			if(0==(i&(((1<<20)/4)-1)))
			{
				EdbgOutputDebugString(".");
			}
		}

		EdbgOutputDebugString("\r\nwrite ram done at:0x%x, start check\r\n", start+i*4);

		pi=(int*)start;
		for(i=0; i<(len/4); i++, pi++)
		{
			if(0==(i&(((1<<20)/4)-1)))
			{
				EdbgOutputDebugString(".");
			}

			if((*pi)!=(j?(*pi=(~i)):(*pi=i)))
			{
				EdbgOutputDebugString("error addr:0x%x, 0x%x!=0x%x\r\n", start+i*4, *pi, (j?(*pi=(~i)):(*pi=i)));
				err++;
			}
		}
		EdbgOutputDebugString("\r\ncheck twice\r\n");
		pi=(int*)start;
		for(i=0; i<(len/4); i++, pi++)
		{
			if(0==(i&(((1<<20)/4)-1)))
			{
				EdbgOutputDebugString(".");
			}

			if((*pi)!=(j?(*pi=(~i)):(*pi=i)))
			{
				EdbgOutputDebugString("error addr:0x%x, 0x%x!=0x%x\r\n", start+i*4, *pi, (j?(*pi=(~i)):(*pi=i)));
				err++;
			}
		}

		EdbgOutputDebugString("\r\ncheck ram done at:0x%x, error number:0x%x\r\n", start+i*4, err);
	}
}

void  test_ram2(int start, int len)
{
	BYTE* pb=(BYTE*)start;
	BYTE* pb2;
	int i;

	EdbgOutputDebugString("start memX check ram bgn:0x%x, len:0x%x\r\n", start, len);

	EdbgOutputDebugString("memset 0xff\r\n");
	memset(pb, 0xff, len);
	for(i=0; i<len; i++, pb++)
	{
		if(0xff!=*pb)
		{
			EdbgOutputDebugString("memset error addr:0x%x, 0x%x!=0xff\r\n", pb, *pb);
		}
		if(0==(i&((1<<20)-1)))
		{
			EdbgOutputDebugString(".");
		}
	}

	EdbgOutputDebugString("\r\nmemset 0x0\r\n");
	pb=(BYTE*)start;
	memset(pb, 0x0, len);
	for(i=0; i<len; i++, pb++)
	{
		if(0x0!=*pb)
		{
			EdbgOutputDebugString("memset error addr:0x%x, 0x%x!=0x0\r\n", pb, *pb);
		}
		if(0==(i&((1<<2)-1)))
		{
			EdbgOutputDebugString(".");
		}
	}

	
	EdbgOutputDebugString("\r\nmem set cpy cmp 0xff\r\n");
	pb=(BYTE*)start;
	pb2=pb+len/2;
	memset(pb, 0xff, len/2);
	memcpy(pb2, pb, len/2);
	if(0!=memcmp(pb, pb2, len/2))
	{
		for(i=0; i<len/2; i++, pb++, pb2++)
		{
			if( (0xff!=*pb) || (0xff!=*pb2))
			{
				EdbgOutputDebugString("[0x%x]:0x%x, [0x%x]:0x%x not 0xff\r\n", pb, *pb, pb2, *pb2);
			}
		}
	}
	
	EdbgOutputDebugString("mem set cpy cmp 0x0\r\n");
	pb=(BYTE*)start;
	pb2=pb+len/2;
	memset(pb, 0x0, len/2);
	memcpy(pb2, pb, len/2);
	if(0!=memcmp(pb, pb2, len/2))
	{
		for(i=0; i<len/2; i++, pb++, pb2++)
		{
			if( (0x0!=*pb) || (0x0!=*pb2))
			{
				EdbgOutputDebugString("[0x%x]:0x%x, [0x%x]:0x%x not 0x0\r\n", pb, *pb, pb2, *pb2);
			}
		}
	}
	
	EdbgOutputDebugString("mem set cpy cmp 0xff\r\n");
	pb=(BYTE*)start;
	pb2=pb+len/2;
	memset(pb2, 0xff, len/2);
	memcpy(pb, pb2, len/2);
	if(0!=memcmp(pb2, pb, len/2))
	{
		for(i=0; i<len/2; i++, pb++, pb2++)
		{
			if( (0xff!=*pb) || (0xff!=*pb2))
			{
				EdbgOutputDebugString("[0x%x]:0x%x, [0x%x]:0x%x not 0xff\r\n", pb, *pb, pb2, *pb2);
			}
		}
	}
	
	EdbgOutputDebugString("mem set cpy cmp 0x0\r\n");
	pb=(BYTE*)start;
	pb2=pb+len/2;
	memset(pb2, 0x0, len/2);
	memcpy(pb, pb2, len/2);
	if(0!=memcmp(pb, pb2, len/2))
	{
		for(i=0; i<len/2; i++, pb++, pb2++)
		{
			if( (0x0!=*pb) || (0x0!=*pb2))
			{
				EdbgOutputDebugString("[0x%x]:0x%x, [0x%x]:0x%x not 0x0\r\n", pb, *pb, pb2, *pb2);
			}
		}
	}
	
}
void  test_ram3(int start, int len)
{
	int i, j, k;
	BYTE *pb, *pb1;
	DWORD* pdw=(DWORD*)(start+len/2);

	EdbgOutputDebugString("\r\ntest_ram3\r\n");
	for(i=0; i<len/4/2; i++)
	{
		pdw[i]=0xffffffff;
	}

	j=0;
	i=1;
	pb=(BYTE*)start;
	pb1=pb;
	do
	{
		EdbgOutputDebugString(".");
		memcpy(pb, pb1, i);
		if(0!=memcmp(pb, pb1, i))
		{
			EdbgOutputDebugString("memcpy faild tgt:0x%x src:0x%x len:0x%x\r\n", pb, pb1, i);

			for(k=0; k<i; k++)
			{
				if( (0xff!=pb[k]) || (0xff!=pb1[k]))
				{
					EdbgOutputDebugString("[0x%x]:0x%x, [0x%x]:0x%x not 0xff\r\n", pb, *pb, pb1, *pb1);
					return;
				}
			}
		}

		i++;
	}while(i<(start+len/2));
}


BYTE busb1[0x200];
BYTE busb2[0x5a];
DWORD dwRsv1;
BYTE buf5a[0x25a];
DWORD dwRsv2;
BYTE bufa5[0x25a];
DWORD dwRsv3;
BYTE busb1_[0x200];
BYTE busb2_[0x5a];
DWORD dwRsv4;
BYTE brndis[0x25a];
DWORD dwRsv5;
BYTE bEther[0x22e];
DWORD dwRsv6;
BYTE bTftp[516];

BYTE bAddr[4];
BYTE bLen[4];
BYTE bSig[7];

DWORD* pdwAsicBgn=(DWORD*)0xa3b00000;
DWORD* pdwAsicEnd=(DWORD*)0xa3b00004;
DWORD* pdwAsicErrCode=(DWORD*)0xa3b00008;


void OutCmpDiff(BYTE* ptgt, BYTE* psrc, DWORD dwLen)
{
	DWORD i;

	EdbgOutputDebugString("cmpdiff 0x%x with 0x%x\r\n", ptgt, psrc);
	
	for(i=0; i<dwLen; i++)
	{
		if(*ptgt!=*psrc)
		{
			EdbgOutputDebugString("0x%x != 0x%x at 0x%x\r\n", *ptgt, *psrc, i);
		}

		ptgt++;
		psrc++;
	}
}

VOID OALFlushDCache();
VOID OALCleanDCache();
VOID OALFlushICache();
VOID OALFlushICacheLines( VOID *pAddress, UINT32 size);
void  test_ram4()
{
	BYTE* pImg=(BYTE*)0x80200000;
	DWORD j, i=0;
*pdwAsicBgn=0x006e6762;		//'bgn'
*pdwAsicErrCode=0x00006b6f;	//'ok'
	EdbgOutputDebugString("\r\ntest_ram4\r\n");
	memset(busb1, 0x5a, sizeof(busb1));
	memset(busb2, 0x5a, sizeof(busb2));
	memset(busb1_, 0xa5, sizeof(busb1_));
	memset(busb2_, 0xa5, sizeof(busb2_));

	memset(buf5a, 0x5a, sizeof(buf5a));
	memset(bufa5, 0xa5, sizeof(bufa5));
	
	memcpy(brndis, busb1, sizeof(busb1));
	memcpy(brndis+sizeof(busb1), busb2, sizeof(busb2));
	if(0!=memcmp(brndis, buf5a, sizeof(brndis)))
	{
		EdbgOutputDebugString("memcpy faild at %d times cmp rndis\r\n", 0);
		OutCmpDiff(brndis, buf5a, sizeof(brndis));
		return;
	}

	memcpy(bEther, brndis+44, sizeof(bEther));
	if(0!=memcmp(bEther, buf5a, sizeof(bEther)))
	{
		EdbgOutputDebugString("memcpy faild at %d times cmp rndis\r\n", 0);
		OutCmpDiff(bEther, buf5a, sizeof(bEther));
		return;
	}

	memcpy(bTftp, bEther+42, sizeof(bTftp));
	if(0!=memcmp(bTftp, buf5a, sizeof(bTftp)))
	{
		EdbgOutputDebugString("memcpy faild at %d times cmp tfpt\r\n", 0);
		OutCmpDiff(bTftp, buf5a, sizeof(bTftp));
		return;
	}

	memcpy(bSig, bTftp+4, sizeof(bSig));
	if(0!=memcmp(bSig, buf5a, sizeof(bSig)))
	{
		EdbgOutputDebugString("memcpy faild at %d times cmp sig\r\n", 0);
		OutCmpDiff(bSig, buf5a, sizeof(bSig));
		return;
	}

	memcpy(bAddr, bTftp+4+7, sizeof(bAddr));
	if(0!=memcmp(bAddr, buf5a, sizeof(bAddr)))
	{
		EdbgOutputDebugString("memcpy faild at %d times cmp dwAddr\r\n", 0);
		OutCmpDiff(bAddr, buf5a, sizeof(bAddr));
		return;
	}

	memcpy(bLen, bTftp+4+7+4, sizeof(bLen));
	if(0!=memcmp(bLen, buf5a, sizeof(bLen)))
	{
		EdbgOutputDebugString("memcpy faild at %d times cmp len\r\n", 0);
		OutCmpDiff(bLen, buf5a, sizeof(bLen));
		return;
	}

	memcpy(pImg, bTftp+4+7+4+4, sizeof(bTftp)-(4+7+4+4));
	if(0!=memcmp(pImg, buf5a, sizeof(bTftp)-(4+7+4+4)))
	{
		EdbgOutputDebugString("memcpy faild at %d times cmp img\r\n", 0);
		OutCmpDiff(pImg, buf5a, sizeof(bTftp)-(4+7+4+4));
		return;
	}

	pImg+=(sizeof(bTftp)-(4+7+4+4));
	i++;
//OALCleanDCache();
OALFlushICache();
OALFlushICacheLines(memcpy, 32*2);

for(j=0; j<10; j++)
{
	while(pImg<(BYTE*)0x81200000)
	{
		memcpy(brndis, busb1_, sizeof(busb1_));
//OALCleanDCache();
OALFlushICache();
//OALFlushICacheLines((BYTE*)test_ram4+0x2d0, 32*4);
		memcpy(brndis+sizeof(busb1_), busb2_, sizeof(busb2_));
//OALCleanDCache();
OALFlushICache();
//OALFlushICacheLines((BYTE*)test_ram4+0x2E0, 32*4);
		if(0!=memcmp(brndis, bufa5, sizeof(brndis)))
		{
			EdbgOutputDebugString("memcpy faild at %d times cmp rndis\r\n", i);
			OutCmpDiff(brndis, bufa5, sizeof(brndis));
//			return;
		}
		
		memcpy(bEther, brndis+44, sizeof(bEther));
		if(0!=memcmp(bEther, bufa5, sizeof(bEther)))
		{
			EdbgOutputDebugString("memcpy faild at %d times cmp bEther\r\n", i);
			OutCmpDiff(bEther, bufa5, sizeof(bEther));
//			return;
		}
		
		memcpy(bTftp, bEther+42, sizeof(bTftp));
		if(0!=memcmp(bTftp, bufa5, sizeof(bTftp)))
		{
			EdbgOutputDebugString("memcpy faild at %d times cmp tfpt\r\n", i);
			OutCmpDiff(bTftp, bufa5, sizeof(bTftp));
//			return;
		}

		memcpy(pImg, bTftp, sizeof(bTftp));
		if(0!=memcmp(pImg, bufa5, sizeof(bTftp)))
		{
			EdbgOutputDebugString("memcpy faild at %d times cmp img\r\n", i);
			OutCmpDiff(pImg, bufa5, sizeof(bTftp));
//			return;
		}

		pImg+=sizeof(bTftp);
		i++;

		memcpy(brndis, busb1, sizeof(busb1));
		memcpy(brndis+sizeof(busb1), busb2, sizeof(busb2));
		if(0!=memcmp(brndis, buf5a, sizeof(brndis)))
		{
			EdbgOutputDebugString("memcpy faild at %d times cmp rndis\r\n", i);
			OutCmpDiff(brndis, buf5a, sizeof(brndis));
//			return;
		}
		
		memcpy(bEther, brndis+44, sizeof(bEther));
		if(0!=memcmp(bEther, buf5a, sizeof(bEther)))
		{
			EdbgOutputDebugString("memcpy faild at %d times cmp bEther\r\n", i);
			OutCmpDiff(bEther, buf5a, sizeof(bEther));
//			return;
		}
		
		memcpy(bTftp, bEther+42, sizeof(bTftp));
		if(0!=memcmp(bTftp, buf5a, sizeof(bTftp)))
		{
			EdbgOutputDebugString("memcpy faild at %d times cmp tfpt\r\n", i);
			OutCmpDiff(bTftp, buf5a, sizeof(bTftp));
//			return;
		}
		
		memcpy(pImg, bTftp, sizeof(bTftp));
		if(0!=memcmp(pImg, buf5a, sizeof(bTftp)))
		{
			EdbgOutputDebugString("memcpy faild at %d times cmp img\r\n", i);
			OutCmpDiff(pImg, buf5a, sizeof(bTftp));
//			return;
		}
			
		pImg+=sizeof(bTftp);
		i++;
	}
	pImg=(BYTE*)(0x80200000+j);
}
//g_fAsic=FALSE;
//for(i=0;i<100;i++){*pdwAsicEnd=0x00646e65;}		//'end'

}


void DumpData(BYTE* pbuf, DWORD dwLen)
{
	DWORD i;
	BYTE buf[17];
	BYTE tmp;

	buf[16]=0;
	for(i=0; i<dwLen; i++)
	{
		tmp=*pbuf;
		if( (0x20>tmp) || (0x7e<tmp) )
		{
			buf[i&0xf]='.';
		}
		else
		{
			buf[i&0xf]=tmp;
		}

		if(0xf==(i&0xf))
		{
			if(tmp>0xf)
			{
				EdbgOutputDebugString("%x %s\r\n", tmp, buf);
			}
			else
			{
				EdbgOutputDebugString("0%x %s\r\n", tmp, buf);
			}
		}
		else if(0x3==(i&3))
		{
			if(tmp>0xf)
			{
				EdbgOutputDebugString("%x ", tmp);
			}
			else
			{
				EdbgOutputDebugString("0%x ", tmp);
			}
		}
		else
		{
			if(tmp>0xf)
			{
				EdbgOutputDebugString("%x", tmp);
			}
			else
			{
				EdbgOutputDebugString("0%x", tmp);
			}
		}
		pbuf++;
	}

}

_inline DWORD Stream2Dword(BYTE* pbData)
{
	return (pbData[0]|(pbData[1]<<8)|(pbData[2]<<16)|(pbData[3]<<24));
}
_inline void Dword2Stream(DWORD dw, BYTE* pbData)
{
	pbData[0]=(BYTE)(dw&0xff);
	pbData[1]=(BYTE)((dw>>8)&0xff);
	pbData[2]=(BYTE)((dw>>16)&0xff);
	pbData[3]=(BYTE)((dw>>24)&0xff);
}

BOOL ErrorReport(DWORD dwReason, DWORD dwReserved)
{
	AsicDbg();
	AsicEndIndicate();

	g_fDisDbgPort=FALSE;
	EdbgOutputDebugString("HALT reason:0x%x\r\n", dwReason);

	if(g_fFindDif)
	{
		EdbgOutputDebugString("DifRecAddr:0x%x DifBinAddr:0x%x DifRecVal:0x%x DifBinVal:0x%x\r\n"
			,g_dwFirstDifRecAddr, g_dwFirstDifBinAddr, g_bFirstDifRecVal, g_bFirstDifBinVal, g_fFindDif);
	}

	while(1)
	{
		TestMenu(&g_BootConfig);
	}

	return TRUE;
}

void LogData(BYTE btype, BYTE* pbData, DWORD dwLen)
{
	if( (!g_fStartLog) || (0==dwLen) || (g_fDisLog))
	{
		return;
	}

	g_pCurLogAddr[0]=btype;
	g_pCurLogAddr++;

	if( (g_pCurLogAddr+dwLen) >= (BYTE*)(0x84000000-4-4-1) )
	{
		EdbgOutputDebugString("log too much data log addr:0x%x len:0x%x times:0x%x\r\n", g_pCurLogAddr, dwLen, g_dwLogTimes);
		g_fDisLog=TRUE;
		dwLen=(0x84000000-4-4-1)-(DWORD)g_pCurLogAddr;
	}

	Dword2Stream((DWORD)(g_pCurLogAddr+8), g_pCurLogAddr);
	g_pCurLogAddr+=4;

	Dword2Stream(dwLen, g_pCurLogAddr);
	g_pCurLogAddr+=4;

	memcpy(g_pCurLogAddr, pbData, dwLen);
	g_pCurLogAddr+=dwLen;
	g_pCurLogAddr[0]=0x5a;	// end

	g_dwLogTimes++;
}


DWORD GetByteCheckSum(BYTE* pb, DWORD dwLen)
{
	DWORD dwSum, i;

	dwSum=0;
	for(i=0; i<dwLen; i++)
	{
		dwSum+=pb[i];
	}

	return dwSum;
}

DWORD g_dwCheckSum;
BOOL CheckDataSum(BYTE bType, BYTE* pb, DWORD dwLen)
{
	DWORD dwSum;
	return TRUE;

	dwSum=GetByteCheckSum(pb, dwLen);

	if(bType=0xff)
	{
		g_dwCheckSum=dwSum;
	}
	else
	{
		if(g_dwCheckSum!=dwSum)
		{
			EdbgOutputDebugString("type:0x%x CheckDataSum 0x%x !=  0x%x\r\n", bType, g_dwCheckSum, dwSum);
			LogData(bType, pb, dwLen);
			ErrorReport(BLERR_CHECKSUM, 0);
		}
	}

	return TRUE;
}


void USBDownload()
{
	DWORD dwImageStart, dwImageLength, dwLaunchAddr;
	if (!InitUSBEthDevice(&g_BootConfig, &pBSPArgs->kitl))
	{
		EdbgOutputDebugString("ERROR: OEMPlatformInit: Failed to initialize USB Ethernet controller.\r\n");
		return;
	}

	OEMPreDownload();
//	DownloadImage(&dwImageStart, &dwImageLength, &dwLaunchAddr);
}


VOID OutLogInfo()
{
	BYTE bType;
	DWORD dwLen, dwAddr, dwLogNumb;
	BYTE* pb;

	EdbgOutputDebugString("Log info logtimes:%d, start addr:0x%x, end addr:0x%x\r\n", g_dwLogTimes, LOG_BASE_ADDR, g_pCurLogAddr);
	pb=(BYTE*)(LOG_BASE_ADDR);
	dwLogNumb=0;
	while(0x5a!=pb[0])
	{
		bType=pb[0];
		pb++;

		dwAddr=Stream2Dword(pb);
		pb+=4;

		dwLen=Stream2Dword(pb);
		pb+=4;

		EdbgOutputDebugString("type:%d addr:0x%x len:0x%x lognumb:0x%x\r\n", bType, dwAddr, dwLen, dwLogNumb);
		pb+=dwLen;
		dwLogNumb++;
	}
}


VOID DumpLogData()
{
	DWORD i=0;
	BYTE bType, bLogType;
	DWORD dwLen, dwAddr, dwStartAddr, dwPackages, dwLogNumb, dwTypeNumb;
	BYTE* pb;
	BOOL fEsc;

	EdbgOutputDebugString("\r\nPlease input log package type:0x");
	bLogType=(BYTE)GetDebugDword(&fEsc);
	if(fEsc)
	{
		return;
	}

	EdbgOutputDebugString("\r\nPlease input log package start addr:0x");
	dwStartAddr=GetDebugDword(&fEsc);
	if(fEsc)
	{
		return;
	}

	EdbgOutputDebugString("\r\nPlease input package number:0x");
	dwPackages=GetDebugDword(&fEsc);
	if(fEsc)
	{
		return;
	}

	pb=(BYTE*)(LOG_BASE_ADDR);
	dwLogNumb=0;
	dwTypeNumb=0;
	while( (0x5a!=pb[0]) && (dwPackages>0))
	{
		dwLogNumb++;

		bType=pb[0];
		pb++;

		dwAddr=Stream2Dword(pb);
		pb+=4;

		dwLen=Stream2Dword(pb);
		pb+=4;

		if( (dwStartAddr<=dwAddr) && (bType==bLogType) )
		{
			dwTypeNumb++;
			dwPackages--;
			EdbgOutputDebugString("\r\ndump package type:0x%x, addr:0x%x len:0x%x package number:0x%x type numb:0x%x\r\n", bType, dwAddr, dwLen, dwLogNumb, dwTypeNumb);
			DumpData((BYTE*)dwAddr, dwLen);
		}
		pb+=dwLen;
	}
}


void RamTest()
{
//	test_ram(0x80100000, 0x4000000-0x100000);
//	test_ram(0xa0100000, 0x4000000-0x100000);

//	test_ram2(0x80100000, 0x4000000-0x100000);
//	test_ram2(0xa0100000, 0x4000000-0x100000);

//	test_ram3(0x80100000, 0x4000000-0x100000);
//	test_ram3(0xa0100000, 0x4000000-0x100000);

	test_ram4();

}

BOOL TestMenu(PBOOT_CFG pBootCfg)
{
	BYTE KeySelect = 0;
	BOOL bConfigChanged = FALSE;

	// init log system
	g_pOEMReportError=ErrorReport;
	g_pCurLogAddr=(BYTE*)(LOG_BASE_ADDR);
//	memset(g_pCurLogAddr, 0xff, 0x84000000-LOG_BASE_ADDR);
	g_pCurLogAddr[0]=0x5a;
	g_fStartLog=FALSE;
	g_dwLogTimes=0;
	g_fDisLog=TRUE;
	
	Tst_Main(pBootCfg);

	while(TRUE)
	{
		KeySelect = 0;		 
		EdbgOutputDebugString ( "\r\nEthernet Boot Loader test memu:\r\n\r\n");
		EdbgOutputDebugString ( "E) end test menu\r\n");
        EdbgOutputDebugString ( "D) Dwnload by usb\r\n");
        EdbgOutputDebugString ( "L) %s Log Data\r\n", g_fStartLog?"Stop":"Start");
        EdbgOutputDebugString ( "I) Info of log data\r\n");
        EdbgOutputDebugString ( "O) Output log data\r\n");
        EdbgOutputDebugString ( "P) Print data\r\n");
        EdbgOutputDebugString ( "R) Ram test\r\n");
		EdbgOutputDebugString ( "\r\nEnter your selection: ");

		while (! ( 
					( (KeySelect == 'E') || (KeySelect == 'e') ) ||
					( (KeySelect == 'D') || (KeySelect == 'd') ) ||
					( (KeySelect == 'O') || (KeySelect == 'o') ) ||
					( (KeySelect == 'L') || (KeySelect == 'l') ) ||
					( (KeySelect == 'I') || (KeySelect == 'i') ) ||
					( (KeySelect == 'O') || (KeySelect == 'o') ) ||
					( (KeySelect == 'R') || (KeySelect == 'r') )
				   ))
		{
			KeySelect = OEMReadDebugByte();
		}

		EdbgOutputDebugString ( "%c\r\n", KeySelect);

		switch(KeySelect)
		{
		case 'e':
		case 'E':
            goto MENU_DONE;
            break;

		case 'd':
		case 'D':
			USBDownload();
			break;
		
		case 'l':
		case 'L':
			g_fStartLog?(g_fStartLog=FALSE):(g_fStartLog=TRUE);
			break;

		case 'i':
		case 'I':
			OutLogInfo();
			break;

		case 'o':
		case 'O':
			DumpLogData();
			break;
		
		case 'r':
		case 'R':
			RamTest();
			break;

		default:
			break;
		}
	}

MENU_DONE:

	return(TRUE);
}

/*
// replace the real get time to speed up
DWORD g_dwSimuRtc=90;
BOOL OEMGetRealTime(SYSTEMTIME *pTime)
{
	memset(pTime, 0, sizeof(SYSTEMTIME));
	pTime->wSecond=g_dwSimuRtc%60;
	pTime->wMinute=(g_dwSimuRtc/60)%60;
	pTime->wHour=(g_dwSimuRtc/(60*60))%24;

	g_dwSimuRtc++;

	return TRUE;
}

BOOL OEMSetRealTime(LPSYSTEMTIME lpst)
{
	return TRUE;
}

BOOL OALIoCtlHalInitRTC(
    UINT32 code, VOID *pInpBuffer, UINT32 inpSize, VOID *pOutBuffer,
    UINT32 outSize, UINT32 *pOutSize
) 
{
	return TRUE;
}
*/

void DumpMem()
{
	BYTE* pbDump;
	DWORD dwLen;
	BOOL fEsc;

	EdbgOutputDebugString("\r\nPlease input dump addr:0x");
	pbDump=(BYTE*)GetDebugDword(&fEsc);
	if(fEsc)
	{
		return;
	}

	EdbgOutputDebugString("\r\nPlease input dump len:0x");
	dwLen=GetDebugDword(&fEsc);
	if(fEsc)
	{
		return;
	}

	EdbgOutputDebugString("\r\ndump data addr:0x%x len:0x%x\r\n", pbDump, dwLen);
	DumpData(pbDump, dwLen);
}

VOID JumpToAddr()
{
	BOOL fEsc;
	DWORD dwAddr;
	EdbgOutputDebugString ("\r\nplease addr to jump:0x");
	dwAddr=GetDebugDword(&fEsc);
	if(!fEsc)
	{
		BootImage(dwAddr);
	}
}

VOID CmpMem()
{
	BYTE *pbs, *pbt;
	DWORD dwLen, i, dwErr;
	BOOL fEsc;
	
	EdbgOutputDebugString("Cmpmem\r\nSrc:0x");
	pbs=(BYTE*)GetDebugDword(&fEsc);
	if(fEsc)
	{
		return;
	}

	EdbgOutputDebugString("\r\nTgt:0x");
	pbt=(BYTE*)GetDebugDword(&fEsc);
	if(fEsc)
	{
		return;
	}

	EdbgOutputDebugString("\r\nLen:0x");
	dwLen=GetDebugDword(&fEsc);
	if(fEsc)
	{
		return;
	}

	EdbgOutputDebugString("\r\nstarg cmp mem 0x%x <==> 0x%x len:0x%x\r\n", pbs, pbt, dwLen);
	dwErr=0;
	for(i=0; i<dwLen; i++)
	{
		if(pbs[i]!=pbt[i])
		{
			EdbgOutputDebugString("[0x%x]:0x%x != [0x%x]:0x%x\r\n", pbs+i, pbs[i], pbt+i, pbt[i]);
			dwErr++;
			if(dwErr>100)
			{
				EdbgOutputDebugString("too many diffrents stop compare!\r\n");
				return;
			}
		}
	}
//	EdbgOutputDebugString("\r\cmp mem 0x%x <==> 0x%x len:0x%x done!\r\n", pbs, pbt, dwLen);
}


void Timer0_CB(void* pv)
{
static BOOL s_fIdl=FALSE;
//	EdbgOutputDebugString ( "Timer0_CB\r\n");
	if(s_fIdl)
	{
		s_fIdl=FALSE;
	}
	else
	{
		s_fIdl=TRUE;
		Power_Idle();
	}
//	EdbgOutputDebugString ( "Timer0_CB return\r\n");
}
void Timer1_CB(void* pv)
{
//	EdbgOutputDebugString ( "Timer1_CB\r\n");
}

void Tst_Timer()
{
	DWORD dwTimeUs;

	EdbgOutputDebugString ( "Input the time(ms, 0 stop) value for timer:");
	dwTimeUs=GetDebugDword(NULL);
	EdbgOutputDebugString ( "start test interval value:%d\r\n", dwTimeUs);
	
	if(0==dwTimeUs)
	{
		Timer_Start(0, 0, FALSE, 0, 0, 0);		// for irq
		Timer_Start(1, 1, FALSE, 0, 0, 0);		// for fiq
	}
	else
	{
		Timer_Start(0, 0, TRUE, dwTimeUs*1000, Timer0_CB, NULL);
		Timer_Start(1, 1, TRUE, dwTimeUs*1000*2, Timer1_CB, NULL);
	}
}


VOID SimuEbootDown()
{
	DWORD dwTimeUs;
	DWORD dwImageStart, dwImageLength, dwLaunchAddr;

	EdbgOutputDebugString ( "Simu eboot down\r\n");

	EdbgOutputDebugString ( "Input the time(ms, 0 no idel) of idle:");
	dwTimeUs=GetDebugDword(NULL);

	if(0!=dwTimeUs)
	{
		EdbgOutputDebugString ( "enable power idle %dms evry %dms\r\n", dwTimeUs, dwTimeUs*2);
		Timer_Start(0, 0, TRUE, dwTimeUs*1000, Timer0_CB, NULL);
		Timer_Start(1, 1, TRUE, dwTimeUs*1000*2, Timer1_CB, NULL);
	}

	EdbgOutputDebugString ( "Init Simu Device\r\n");
	InitEbSimuDevice(v_pBootCfg);

//g_fDisDbgPort=FALSE;
	EdbgOutputDebugString ( "OEMPreDownload\r\n");
	OEMPreDownload();

	EdbgOutputDebugString ( "DownloadImage\r\n");
//	DownloadImage(&dwImageStart, &dwImageLength, &dwLaunchAddr);

	if(0!=dwTimeUs)
	{
		EdbgOutputDebugString ( "disenable power idle\r\n");
		Timer_Start(0, 0, FALSE, 0, 0, 0);
		Timer_Start(1, 1, FALSE, 0, 0, 0);
	}
g_fDisDbgPort=FALSE;
	EdbgOutputDebugString ( "Simu eboot down ok!\r\n");
}


void Tst_SVC()
{
	SVC_Call_ArgNumb_0(10);
}
struct TstFunc s_TstFunS[]=
{
	TST_FUN(Tst_Timer),
	TST_FUN(Tst_SVC),
	TST_FUN(DumpMem),
	TST_FUN(CmpMem),
	TST_FUN(JumpToAddr),
	TST_FUN(SimuEbootDown),


	{NULL, NULL}
};


